package cn.cj.erp.modules.system.controller;

import cn.cj.erp.bo.system.SysMenuBo;
import cn.cj.erp.common.utils.Convert;
import cn.cj.erp.modules.common.controller.AbstractController;
import cn.cj.erp.common.vo.RoleMenuVo;
import cn.cj.erp.common.enums.LogBusinessTypeEnum;
import cn.cj.erp.common.enums.MenuTypeEnum;
import cn.cj.erp.common.exception.ServiceException;
import cn.cj.erp.common.security.annotation.Log;
import cn.cj.erp.common.http.Result;
import cn.cj.erp.service.system.SysMenuService;
import cn.cj.erp.service.system.SysRoleMenuService;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 系统菜单
 *
 * @author chenjian
 */
@Validated
@Slf4j
@RestController
@RequestMapping("/system/menu")
public class SysMenuController extends AbstractController {
    @Resource
    private SysMenuService sysMenuService;
    @Resource
    private SysRoleMenuService sysRoleMenuService;
    
    /**
     * 列表
     */
    @PostMapping("/queryTree")
    @PreAuthorize("@ss.hasPerm('system:menu:list')")
    public Result<List<SysMenuBo>> queryTree(@RequestBody SysMenuBo params) {
        return Result.query(sysMenuService.queryTree(params));
    }

    /**
     * 菜单信息
     */
    @GetMapping("/info/{id}")
    @PreAuthorize("@ss.hasPerm('system:menu:query')")
    public Result<SysMenuBo> info(@PathVariable("id") Long id) {
        return Result.query(sysMenuService.getById(id));
    }

    /**
     * 获取当前父节点下可用排序号（即没有被使用的排序号）
     */
    @PreAuthorize("@ss.hasPerm('system:dept:query')")
    @GetMapping("/getCurrentUsedOrderNum/{parentId}")
    public Result<Integer> getCurrentUsedOrderNum(@PathVariable("parentId") Long parentId) {
        return Result.query(sysMenuService.getCurrentUsedOrderNum(parentId));
    }

    /**
     * 加载对应角色菜单列表树
     */
    @GetMapping(value = "/roleMenuTree/{roleId}")
    public Result<RoleMenuVo> roleMenuTree(@PathVariable("roleId") Long roleId) {
        Assert.notNull(roleId, "请选择角色");
        List<Long> menuIds = sysRoleMenuService.listMenuIdsByRoleId(roleId);
        // 给前端使用，需要将Long列表转化成String列表
        List<String> checkedKeys = menuIds.stream().map(Convert::toStr).collect(Collectors.toList());
        List<SysMenuBo> menus = sysMenuService.queryTree(new SysMenuBo());
        return Result.ok(new RoleMenuVo(checkedKeys, menus));
    }

    /**
     * 保存
     */
    @PostMapping("/save")
    @PreAuthorize("@ss.hasPerm('system:menu:add')")
    @Log(title = "菜单管理", businessType = LogBusinessTypeEnum.INSERT)
    public Result<Boolean> save(@Valid @RequestBody SysMenuBo sysMenu) {
        //数据校验
        verifyForm(sysMenu);
        return Result.save(sysMenuService.save(sysMenu));
    }

    /**
     * 修改
     */
    @PostMapping("/update")
    @PreAuthorize("@ss.hasPerm('system:menu:edit')")
    @Log(title = "菜单管理", businessType = LogBusinessTypeEnum.UPDATE)
    public Result<Boolean> update(@Valid @RequestBody SysMenuBo sysMenu) {
        //数据校验
        verifyForm(sysMenu);
        return Result.update(sysMenuService.updateById(sysMenu));
    }


    /**
     * 删除
     */
    @PostMapping("/delete/{id}")
    @PreAuthorize("@ss.hasPerm('system:menu:remove')")
    @Log(title = "菜单管理", businessType = LogBusinessTypeEnum.DELETE)
    public Result<Boolean> delete(@PathVariable("id") Long id) {
        return Result.remove(sysMenuService.removeById(id));
    }

    /**
     * 校验名称是否存在
     */
    @PreAuthorize("@ss.hasPerm('system:menu:edit')")
    @GetMapping("/existName")
    public Result<Boolean> existName(SysMenuBo sysMenu) {
        return Result.ok(sysMenuService.existName(sysMenu));
    }

    /**
     * 校验编码是否存在
     */
    @PreAuthorize("@ss.hasPerm('system:menu:edit')")
    @GetMapping("/existCode")
    public Result<Boolean> existCode(SysMenuBo sysMenu) {
        return Result.ok(sysMenuService.existCode(sysMenu));
    }

    /**
     * 验证参数是否正确
     */
    private void verifyForm(SysMenuBo menu) {
        //菜单
        if (MenuTypeEnum.MENU.equals(menu.getMenuType())) {
            if (StrUtil.isBlank(menu.getPath())) {
                throw new ServiceException("路由地址不能为空");
            }
        }
        //上级菜单类型
        MenuTypeEnum parentType = MenuTypeEnum.CATALOG;
        if (menu.getParentId() != 0) {
            SysMenuBo parent = sysMenuService.getById(menu.getParentId());
            if (parent == null) {
                throw new ServiceException("上级菜单不存在");
            }
            parentType = parent.getMenuType();
        }
        if (menu.getMenuType() == null) {
            throw new ServiceException("菜单类型错误");
        }
        if (MenuTypeEnum.CATALOG.equals(menu.getMenuType()) && !MenuTypeEnum.CATALOG.equals(parentType)) {
            throw new ServiceException("目录的上级只能为目录");
        }
        if (MenuTypeEnum.MENU.equals(menu.getMenuType()) && !MenuTypeEnum.CATALOG.equals(parentType)) {
            throw new ServiceException("菜单的上级只能为目录");
        }
        if (MenuTypeEnum.BUTTON.equals(menu.getMenuType()) && !MenuTypeEnum.MENU.equals(parentType)) {
            throw new ServiceException("按钮的上级只能为菜单");
        }
    }
}
